package log

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/config"
	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/pkg/gin/log/logger"
	gormLogger "gorm.io/gorm/logger"
	gormUtil "gorm.io/gorm/utils"
	"time"
)

const (
	key = "IkibX71IEf382PTF"
	iv  = "IkibX71IEf382PTF"
)

var (
	TeamsLog *logger.Logger
	Config   *logger.Config
)

func init() {
	if config.C.Debug {
		Config = logger.DebugConfig()
		TeamsLog = logger.New(Config)
	} else {
		TeamsLog = logger.New(nil)
		Config = TeamsLog.Config
	}

}

// 应用更新配置文件
func WithConfig() {
	TeamsLog.WithConfig(config.C.Debug, true)
}

func Debug(args ...interface{}) {
	TeamsLog.Debug(args...)
}

func Debugf(template string, args ...interface{}) {
	TeamsLog.Debugf(template, args...)
}

func Info(args ...interface{}) {
	TeamsLog.Info(args...)
}

func Infof(template string, args ...interface{}) {
	TeamsLog.Infof(template, args...)
}

func Warn(args ...interface{}) {
	TeamsLog.Warn(args...)
}

func Warnf(template string, args ...interface{}) {
	TeamsLog.Warnf(template, args...)
}

func Error(args ...interface{}) {
	TeamsLog.Error(args...)
}

func Errorf(template string, args ...interface{}) {
	TeamsLog.Errorf(template, args...)
}

func Fatal(args ...interface{}) {
	TeamsLog.Fatal(args...)
}

func Fatalf(template string, args ...interface{}) {
	TeamsLog.Fatalf(template, args...)
}

func Panic(args ...interface{}) {
	TeamsLog.Panic(args...)
}

func Panicf(template string, args ...interface{}) {
	TeamsLog.Panicf(template, args...)
}

type GormLog struct {
	gormLogger.Config
	gormLogger.LogLevel
	infoStr, warnStr, errStr            string
	traceStr, traceErrStr, traceWarnStr string
}

const (
	Statement string = "Statement"
	TimeMs    string = "TimeMs"
)

type gormLogStruct struct {
	FileWithLineNum string  `json:"FileWithLineNum"`
	Statement       string  `json:"Statement"`
	TimeMs          float64 `json:"TimeMs"`
	Row             int64   `json:"Row"`
	SlowStatement   string  `json:"SlowStatement"`
	Err             string  `json:"Err"`
}

func NewGorm() *GormLog {
	var (
		infoStr      = "%s\n[info] "
		warnStr      = "%s\n[warn] "
		errStr       = "%s\n[error] "
		traceStr     = "%s\n[%.3fms] [rows:%v] %s"
		traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s"
		traceErrStr  = "%s %s\n[%.3fms] [rows:%v] %s"
		//infoStr      = "{\"" + Statement + "\":\"【info】:%s\"}"
		//warnStr      = "{\"" + Statement + "\":\"【warn】:%s\"}"
		//errStr       = "{\"" + Statement + "\":\"【err】:%s\"}"
		//traceStr     = "{\"【info】FileWithLineNum\":\"%s\", \"TimeMs\":%.3f, \"Row\":\"%v\", \"" + Statement + "\":\"%s\"}"
		//traceWarnStr = "{\"【warn】FileWithLineNum\":\"%s\",  \"SlowStatement\":\"%s\",  \"TimeMs\":%.3f, \"Row\":\"%v\", \"" + Statement + "\":\"%s\"}"
		//traceErrStr  = "{\"【err】FileWithLineNum\":\"%s\", \"Err\":\"%s\",  \"TimeMs\":%.3f, \"Row\":\"%v\", \"" + Statement + "\":\"%s\"}"
	)
	return &GormLog{
		infoStr:      infoStr,
		warnStr:      warnStr,
		errStr:       errStr,
		traceStr:     traceStr,
		traceWarnStr: traceWarnStr,
		traceErrStr:  traceErrStr,
		Config: gormLogger.Config{
			SlowThreshold:             200 * time.Millisecond, // Slow SQL threshold
			LogLevel:                  gormLogger.Info,        // Log level
			IgnoreRecordNotFoundError: true,                   // Ignore ErrRecordNotFound error for logger
		},
	}
}

func (gl *GormLog) LogMode(level gormLogger.LogLevel) gormLogger.Interface {
	gl.LogLevel = level
	return gl
}
func (gl *GormLog) Info(ctx context.Context, msg string, arg ...interface{}) {
	TeamsLog.Infof(gl.infoStr+msg, append([]interface{}{gormUtil.FileWithLineNum()}, arg...)...)
}
func (gl *GormLog) Warn(ctx context.Context, msg string, arg ...interface{}) {
	TeamsLog.Warnf(gl.warnStr+msg, append([]interface{}{gormUtil.FileWithLineNum()}, arg...)...)
}
func (gl *GormLog) Error(ctx context.Context, msg string, arg ...interface{}) {
	TeamsLog.Errorf(gl.errStr+msg, append([]interface{}{gormUtil.FileWithLineNum()}, arg...)...)
}
func (gl *GormLog) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
	elapsed := time.Since(begin)
	sql, rows := fc()
	var gls gormLogStruct
	gls.FileWithLineNum = gormUtil.FileWithLineNum()
	if err != nil {
		gls.Err = err.Error()
	}
	gls.TimeMs = float64(elapsed.Nanoseconds()) / 1e6
	gls.Statement = sql
	gls.Row = rows
	switch {
	case err != nil && gl.LogLevel >= gormLogger.Error && (!errors.Is(err, gormLogger.ErrRecordNotFound) || !gl.IgnoreRecordNotFoundError):
		glsByte, _ := json.Marshal(&gls)
		glsStr := string(glsByte)
		if rows == -1 {
			TeamsLog.Errorf(glsStr)
		} else {
			TeamsLog.Errorf(glsStr)
		}
	case elapsed > gl.SlowThreshold && gl.SlowThreshold != 0 && gl.LogLevel >= gormLogger.Warn:
		slowLog := fmt.Sprintf("SLOW Statement >= %v", gl.SlowThreshold)
		gls.SlowStatement = slowLog
		glsByte, _ := json.Marshal(&gls)
		glsStr := string(glsByte)
		if rows == -1 {
			TeamsLog.Warnf(glsStr)
		} else {
			TeamsLog.Warnf(glsStr)
		}
	case gl.LogLevel == gormLogger.Info:
		glsByte, _ := json.Marshal(&gls)
		glsStr := string(glsByte)
		if rows == -1 {
			TeamsLog.Infof(glsStr)
		} else {
			TeamsLog.Infof(glsStr)
		}
	}
}
